/**
 * @file oled.c
 * @brief OLED SSD1306 驱动实现 (DMA缓存模式)
 * @version 2.0
 * @date 2025-10-03
 * 
 * 硬件连接:
 *   OLED SSD1306  ->  MSPM0G3507
 *   VCC           ->  3.3V
 *   GND           ->  GND
 *   SCK           ->  PB16 (SPI1_SCLK)
 *   MOSI (SDA)    ->  PB15 (SPI1_PICO)
 *   CS            ->  PB17 (SPI1_CS1)
 *   DC            ->  PB14 (SPI Command/Data自动控制)
 *   RES           ->  PB18 (GPIO输出)
 * 
 * 工作原理:
 *   1. 用户修改 oled_buffer 缓存内容
 *   2. DMA 自动从缓存读取数据
 *   3. 通过 SPI 发送到 OLED
 *   4. 循环刷新，无需 CPU 干预
 */

#include "config.h"

// ========== 硬件控制宏定义 ==========
#define OLED_RES_HIGH() DL_GPIO_setPins(GPIOB, OLED_RES_PIN)
#define OLED_RES_LOW() DL_GPIO_clearPins(GPIOB, OLED_RES_PIN)

// ========== 全局变量 ==========
/**
 * 显示缓存：1024字节 (128列 × 8页)
 * 格式：列式存储，每字节代表垂直8个像素
 * buffer[0] = 列0, 页0 (像素 0,0 到 0,7)
 * buffer[1] = 列1, 页0 (像素 1,0 到 1,7)
 * ...
 * buffer[128] = 列0, 页1 (像素 0,8 到 0,15)
 * 
 * 注意：DMA会持续从这个缓存读取数据刷新屏幕
 * 用户只需要修改这个缓存，硬件会自动刷新到OLED
 */
static uint8_t oled_buffer[OLED_BUFFER_SIZE];

/**
 * DMA初始化标志
 */
static bool dma_initialized = false;

// ========== 私有函数 ==========
/**
 * @brief 硬件SPI写字节
 * @param dat 要写入的数据
 */
static void OLED_SPI_WriteByte(uint8_t dat)
{
    // 等待 SPI 空闲
    while (DL_SPI_isBusy(SPI_1_INST))
    {
        // 等待
    }

    // 发送数据
    DL_SPI_transmitData8(SPI_1_INST, dat);

    // 等待发送完成
    while (DL_SPI_isBusy(SPI_1_INST))
    {
        // 等待
    }
}

// 写数据或命令到 OLED
void OLED_WR_Byte(uint8_t dat, uint8_t cmd)
{
    if (cmd)
    {
        // 写数据: 设置 SPI 为数据模式 (DC 引脚自动变高)
        DL_SPI_setControllerCommandDataModeConfig(SPI_1_INST, DL_SPI_CD_MODE_DATA);
    }
    else
    {
        // 写命令: 设置 SPI 为命令模式 (DC 引脚自动变低)
        DL_SPI_setControllerCommandDataModeConfig(SPI_1_INST, DL_SPI_CD_MODE_COMMAND);
    }
    OLED_SPI_WriteByte(dat);
}

// ========== 公共函数实现 ==========

/**
 * @brief OLED初始化
 * @note 包含硬件复位、SSD1306配置、DMA启动
 */
void OLED_Init(void)
{
    // 确保 SPI 已在 System_init() 中完成初始化
    // 硬件复位
    OLED_RES_LOW(); // 复位拉低
    delay_ms(100);
    OLED_RES_HIGH(); // 复位拉高
    delay_ms(100);

    // SSD1306 初始化序列 (适用于 128x64 OLED)
    OLED_WR_Byte(0xAE, OLED_CMD); // 关闭显示

    // 设置时钟分频因子，震荡频率
    OLED_WR_Byte(0xD5, OLED_CMD);
    OLED_WR_Byte(0x80, OLED_CMD);

    // 设置驱动路数
    OLED_WR_Byte(0xA8, OLED_CMD);
    OLED_WR_Byte(0x3F, OLED_CMD); // 默认0x3F(1/64)

    // 设置显示偏移
    OLED_WR_Byte(0xD3, OLED_CMD);
    OLED_WR_Byte(0x00, OLED_CMD); // 默认为0

    // 设置显示开始行 [5:0]
    OLED_WR_Byte(0x40, OLED_CMD);

    // 电荷泵设置
    OLED_WR_Byte(0x8D, OLED_CMD);
    OLED_WR_Byte(0x14, OLED_CMD); // bit2，开启/关闭

    // 设置内存地址模式
    OLED_WR_Byte(0x20, OLED_CMD);
    OLED_WR_Byte(0x02, OLED_CMD); // [1:0],00，列地址模式;01，行地址模式;10,页地址模式;默认10;

    // 段重定义设置,bit0:0,0->0;1,0->127;
    OLED_WR_Byte(0xA1, OLED_CMD);

    // 设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
    OLED_WR_Byte(0xC8, OLED_CMD);

    // 设置COM硬件引脚配置
    OLED_WR_Byte(0xDA, OLED_CMD);
    OLED_WR_Byte(0x12, OLED_CMD);

    // 对比度设置
    OLED_WR_Byte(0x81, OLED_CMD);
    OLED_WR_Byte(0xEF, OLED_CMD); // 1~255;默认0x7F (亮度设置,越大越亮)

    // 设置预充电周期
    OLED_WR_Byte(0xD9, OLED_CMD);
    OLED_WR_Byte(0xF1, OLED_CMD); // [3:0],PHASE 1;[7:4],PHASE 2;

    // 设置VCOMH 电压倍率
    OLED_WR_Byte(0xDB, OLED_CMD);
    OLED_WR_Byte(0x30, OLED_CMD); // [6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;

    // 全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
    OLED_WR_Byte(0xA4, OLED_CMD);

    // 设置显示方式;bit0:1,反相显示;0,正常显示
    OLED_WR_Byte(0xA6, OLED_CMD);

    // 开启显示
    OLED_WR_Byte(0xAF, OLED_CMD);

    // 初始化显示缓存
    OLED_ClearBuffer();
    
    // 配置OLED地址模式（一次性配置）
    OLED_WR_Byte(0x20, OLED_CMD); // 设置内存地址模式
    OLED_WR_Byte(0x00, OLED_CMD); // 00=水平地址模式
    
    OLED_WR_Byte(0x21, OLED_CMD); // 设置列地址范围
    OLED_WR_Byte(0, OLED_CMD);    // 起始列地址 = 0
    OLED_WR_Byte(127, OLED_CMD);  // 结束列地址 = 127
    
    OLED_WR_Byte(0x22, OLED_CMD); // 设置页地址范围
    OLED_WR_Byte(0, OLED_CMD);    // 起始页地址 = 0
    OLED_WR_Byte(7, OLED_CMD);    // 结束页地址 = 7
    
    // 设置SPI为数据模式（后续DMA传输都是数据）
    DL_SPI_setControllerCommandDataModeConfig(SPI_1_INST, DL_SPI_CD_MODE_DATA);
    
    // 配置并启动DMA循环传输
    OLED_StartDMA();
}

// ========== 传统直接写入函数（兼容旧代码）==========

/**
 * @brief 清屏（使用直接写入方式）
 * @note 此函数绕过缓存，直接写入OLED
 */
void OLED_Clear(void)
{
    uint8_t i, n;
    for (i = 0; i < 8; i++)
    {
        OLED_WR_Byte(0xB0 + i, OLED_CMD); // 设置页地址（0~7）
        OLED_WR_Byte(0x00, OLED_CMD);     // 设置显示位置—列低地址
        OLED_WR_Byte(0x10, OLED_CMD);     // 设置显示位置—列高地址
        for (n = 0; n < 128; n++)
        {
            OLED_WR_Byte(0, OLED_DATA);
        }
    }
}

/**
 * @brief 填充整个屏幕（使用直接写入方式）
 * @param dat 填充数据 (0x00=全黑, 0xFF=全白)
 * @note 此函数绕过缓存，直接写入OLED
 */
void OLED_Fill(uint8_t dat)
{
    uint8_t i, n;
    for (i = 0; i < 8; i++)
    {
        OLED_WR_Byte(0xB0 + i, OLED_CMD); // 设置页地址（0~7）
        OLED_WR_Byte(0x00, OLED_CMD);     // 设置显示位置—列低地址
        OLED_WR_Byte(0x10, OLED_CMD);     // 设置显示位置—列高地址
        for (n = 0; n < 128; n++)
        {
            OLED_WR_Byte(dat, OLED_DATA);
        }
    }
}

/**
 * @brief 设置光标位置
 * @param x 列地址 (0-127)
 * @param y 页地址 (0-7)
 */
void OLED_Set_Pos(uint8_t x, uint8_t y)
{
    OLED_WR_Byte(0xB0 + y, OLED_CMD);
    OLED_WR_Byte(((x & 0xF0) >> 4) | 0x10, OLED_CMD);
    OLED_WR_Byte((x & 0x0F), OLED_CMD);
}

/**
 * @brief 开启OLED显示
 */
void OLED_Display_On(void)
{
    OLED_WR_Byte(0x8D, OLED_CMD); // SET DCDC命令
    OLED_WR_Byte(0x14, OLED_CMD); // DCDC ON
    OLED_WR_Byte(0xAF, OLED_CMD); // DISPLAY ON
}

/**
 * @brief 关闭OLED显示
 */
void OLED_Display_Off(void)
{
    OLED_WR_Byte(0x8D, OLED_CMD); // SET DCDC命令
    OLED_WR_Byte(0x10, OLED_CMD); // DCDC OFF
    OLED_WR_Byte(0xAE, OLED_CMD); // DISPLAY OFF
}

/**
 * @brief 颜色反转
 * @param i 0=正常显示, 1=反色显示
 */
void OLED_ColorTurn(uint8_t i)
{
    if (i == 0)
    {
        OLED_WR_Byte(0xA6, OLED_CMD); // 正常显示
    }
    if (i == 1)
    {
        OLED_WR_Byte(0xA7, OLED_CMD); // 反色显示
    }
}

/**
 * @brief 屏幕旋转180度
 * @param i 0=正常显示, 1=旋转180度
 */
void OLED_DisplayTurn(uint8_t i)
{
    if (i == 0)
    {
        OLED_WR_Byte(0xC8, OLED_CMD); // 正常显示
        OLED_WR_Byte(0xA1, OLED_CMD);
    }
    if (i == 1)
    {
        OLED_WR_Byte(0xC0, OLED_CMD); // 反转显示
        OLED_WR_Byte(0xA0, OLED_CMD);
    }
}

// ========== DMA缓存模式函数 ==========

/**
 * @brief 获取显示缓存指针
 * @return 显示缓存的指针
 */
uint8_t* OLED_GetBuffer(void)
{
    return oled_buffer;
}

/**
 * @brief 清空显示缓存
 */
void OLED_ClearBuffer(void)
{
    memset(oled_buffer, 0x00, OLED_BUFFER_SIZE);
}

/**
 * @brief 填充整个缓存
 * @param color 填充的颜色值 (0x00=黑, 0xFF=白)
 */
void OLED_FillBuffer(uint8_t color)
{
    memset(oled_buffer, color, OLED_BUFFER_SIZE);
}

/**
 * @brief 启动DMA循环传输
 * @note 配置DMA后，硬件会自动循环读取oled_buffer并刷新到OLED
 *       用户只需要修改oled_buffer的内容即可，无需手动调用刷新函数
 */
void OLED_StartDMA(void)
{
    if (dma_initialized)
    {
        return;  // 已经初始化过，无需重复配置
    }
    
    // 配置DMA通道
    // 注意：确保syscfg中已配置DMA_CH0用于SPI传输
    DL_DMA_setSrcAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t)oled_buffer);
    DL_DMA_setDestAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t)&SPI_1_INST->TXDATA);
    DL_DMA_setTransferSize(DMA, DMA_CH0_CHAN_ID, OLED_BUFFER_SIZE);
    
    // 启用DMA通道
    DL_DMA_enableChannel(DMA, DMA_CH0_CHAN_ID);

    dma_initialized = true;
}


/**
 * @brief 停止DMA传输（如果需要临时停止）
 */
void OLED_StopDMA(void)
{
    DL_DMA_disableChannel(DMA, DMA_CH0_CHAN_ID);
    dma_initialized = false;
}

/**
 * @brief 重新启动DMA传输
 */
void OLED_RestartDMA(void)
{
    OLED_StopDMA();
    OLED_StartDMA();
}

/**
 * @brief 在缓存中设置像素点
 * @param x X坐标 (0-127)
 * @param y Y坐标 (0-63)
 * @param color 颜色 (0=黑, 1=白)
 */
void OLED_DrawPixel(uint8_t x, uint8_t y, uint8_t color)
{
    if (x >= OLED_WIDTH || y >= OLED_HEIGHT)
        return;
    
    uint16_t index = x + (y / 8) * OLED_WIDTH;
    uint8_t bit = y % 8;
    
    if (color)
    {
        oled_buffer[index] |= (1 << bit);  // 设置为白色
    }
    else
    {
        oled_buffer[index] &= ~(1 << bit); // 设置为黑色
    }
}

/**
 * @brief 在缓存中绘制水平线
 * @param x 起始X坐标
 * @param y Y坐标
 * @param w 线的宽度（像素数）
 * @param color 颜色 (0=黑, 1=白)
 */
void OLED_DrawHLine(uint8_t x, uint8_t y, uint8_t w, uint8_t color)
{
    for (uint8_t i = 0; i < w; i++)
    {
        OLED_DrawPixel(x + i, y, color);
    }
}

/**
 * @brief 在缓存中绘制垂直线
 * @param x X坐标
 * @param y 起始Y坐标
 * @param h 线的高度（像素数）
 * @param color 颜色 (0=黑, 1=白)
 */
void OLED_DrawVLine(uint8_t x, uint8_t y, uint8_t h, uint8_t color)
{
    for (uint8_t i = 0; i < h; i++)
    {
        OLED_DrawPixel(x, y + i, color);
    }
}

/**
 * @brief 在缓存中绘制矩形边框
 * @param x 左上角X坐标
 * @param y 左上角Y坐标
 * @param w 矩形宽度
 * @param h 矩形高度
 * @param color 颜色 (0=黑, 1=白)
 */
void OLED_DrawRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color)
{
    OLED_DrawHLine(x, y, w, color);         // 上边
    OLED_DrawHLine(x, y + h - 1, w, color); // 下边
    OLED_DrawVLine(x, y, h, color);         // 左边
    OLED_DrawVLine(x + w - 1, y, h, color); // 右边
}

/**
 * @brief 在缓存中填充矩形
 * @param x 左上角X坐标
 * @param y 左上角Y坐标
 * @param w 矩形宽度
 * @param h 矩形高度
 * @param color 颜色 (0=黑, 1=白)
 */
void OLED_FillRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color)
{
    for (uint8_t i = 0; i < h; i++)
    {
        OLED_DrawHLine(x, y + i, w, color);
    }
}

// ========== 字符显示函数 ==========

/**
 * @brief 5x7 ASCII 字体库（空格到~，共95个字符）
 * 每个字符5列，每列7位（最高位不用）
 */
static const uint8_t font_5x7[][5] = {
    {0x00, 0x00, 0x00, 0x00, 0x00}, // 空格 (32)
    {0x00, 0x00, 0x5F, 0x00, 0x00}, // !
    {0x00, 0x07, 0x00, 0x07, 0x00}, // "
    {0x14, 0x7F, 0x14, 0x7F, 0x14}, // #
    {0x24, 0x2A, 0x7F, 0x2A, 0x12}, // $
    {0x23, 0x13, 0x08, 0x64, 0x62}, // %
    {0x36, 0x49, 0x55, 0x22, 0x50}, // &
    {0x00, 0x05, 0x03, 0x00, 0x00}, // '
    {0x00, 0x1C, 0x22, 0x41, 0x00}, // (
    {0x00, 0x41, 0x22, 0x1C, 0x00}, // )
    {0x14, 0x08, 0x3E, 0x08, 0x14}, // *
    {0x08, 0x08, 0x3E, 0x08, 0x08}, // +
    {0x00, 0x50, 0x30, 0x00, 0x00}, // ,
    {0x08, 0x08, 0x08, 0x08, 0x08}, // -
    {0x00, 0x60, 0x60, 0x00, 0x00}, // .
    {0x20, 0x10, 0x08, 0x04, 0x02}, // /
    {0x3E, 0x51, 0x49, 0x45, 0x3E}, // 0
    {0x00, 0x42, 0x7F, 0x40, 0x00}, // 1
    {0x42, 0x61, 0x51, 0x49, 0x46}, // 2
    {0x21, 0x41, 0x45, 0x4B, 0x31}, // 3
    {0x18, 0x14, 0x12, 0x7F, 0x10}, // 4
    {0x27, 0x45, 0x45, 0x45, 0x39}, // 5
    {0x3C, 0x4A, 0x49, 0x49, 0x30}, // 6
    {0x01, 0x71, 0x09, 0x05, 0x03}, // 7
    {0x36, 0x49, 0x49, 0x49, 0x36}, // 8
    {0x06, 0x49, 0x49, 0x29, 0x1E}, // 9
    {0x00, 0x36, 0x36, 0x00, 0x00}, // :
    {0x00, 0x56, 0x36, 0x00, 0x00}, // ;
    {0x08, 0x14, 0x22, 0x41, 0x00}, // <
    {0x14, 0x14, 0x14, 0x14, 0x14}, // =
    {0x00, 0x41, 0x22, 0x14, 0x08}, // >
    {0x02, 0x01, 0x51, 0x09, 0x06}, // ?
    {0x32, 0x49, 0x79, 0x41, 0x3E}, // @
    {0x7E, 0x11, 0x11, 0x11, 0x7E}, // A
    {0x7F, 0x49, 0x49, 0x49, 0x36}, // B
    {0x3E, 0x41, 0x41, 0x41, 0x22}, // C
    {0x7F, 0x41, 0x41, 0x22, 0x1C}, // D
    {0x7F, 0x49, 0x49, 0x49, 0x41}, // E
    {0x7F, 0x09, 0x09, 0x09, 0x01}, // F
    {0x3E, 0x41, 0x49, 0x49, 0x7A}, // G
    {0x7F, 0x08, 0x08, 0x08, 0x7F}, // H
    {0x00, 0x41, 0x7F, 0x41, 0x00}, // I
    {0x20, 0x40, 0x41, 0x3F, 0x01}, // J
    {0x7F, 0x08, 0x14, 0x22, 0x41}, // K
    {0x7F, 0x40, 0x40, 0x40, 0x40}, // L
    {0x7F, 0x02, 0x0C, 0x02, 0x7F}, // M
    {0x7F, 0x04, 0x08, 0x10, 0x7F}, // N
    {0x3E, 0x41, 0x41, 0x41, 0x3E}, // O
    {0x7F, 0x09, 0x09, 0x09, 0x06}, // P
    {0x3E, 0x41, 0x51, 0x21, 0x5E}, // Q
    {0x7F, 0x09, 0x19, 0x29, 0x46}, // R
    {0x46, 0x49, 0x49, 0x49, 0x31}, // S
    {0x01, 0x01, 0x7F, 0x01, 0x01}, // T
    {0x3F, 0x40, 0x40, 0x40, 0x3F}, // U
    {0x1F, 0x20, 0x40, 0x20, 0x1F}, // V
    {0x3F, 0x40, 0x38, 0x40, 0x3F}, // W
    {0x63, 0x14, 0x08, 0x14, 0x63}, // X
    {0x07, 0x08, 0x70, 0x08, 0x07}, // Y
    {0x61, 0x51, 0x49, 0x45, 0x43}, // Z
    {0x00, 0x7F, 0x41, 0x41, 0x00}, // [
    {0x02, 0x04, 0x08, 0x10, 0x20}, // backslash
    {0x00, 0x41, 0x41, 0x7F, 0x00}, // ]
    {0x04, 0x02, 0x01, 0x02, 0x04}, // ^
    {0x40, 0x40, 0x40, 0x40, 0x40}, // _
    {0x00, 0x01, 0x02, 0x04, 0x00}, // `
    {0x20, 0x54, 0x54, 0x54, 0x78}, // a
    {0x7F, 0x48, 0x44, 0x44, 0x38}, // b
    {0x38, 0x44, 0x44, 0x44, 0x20}, // c
    {0x38, 0x44, 0x44, 0x48, 0x7F}, // d
    {0x38, 0x54, 0x54, 0x54, 0x18}, // e
    {0x08, 0x7E, 0x09, 0x01, 0x02}, // f
    {0x0C, 0x52, 0x52, 0x52, 0x3E}, // g
    {0x7F, 0x08, 0x04, 0x04, 0x78}, // h
    {0x00, 0x44, 0x7D, 0x40, 0x00}, // i
    {0x20, 0x40, 0x44, 0x3D, 0x00}, // j
    {0x7F, 0x10, 0x28, 0x44, 0x00}, // k
    {0x00, 0x41, 0x7F, 0x40, 0x00}, // l
    {0x7C, 0x04, 0x18, 0x04, 0x78}, // m
    {0x7C, 0x08, 0x04, 0x04, 0x78}, // n
    {0x38, 0x44, 0x44, 0x44, 0x38}, // o
    {0x7C, 0x14, 0x14, 0x14, 0x08}, // p
    {0x08, 0x14, 0x14, 0x18, 0x7C}, // q
    {0x7C, 0x08, 0x04, 0x04, 0x08}, // r
    {0x48, 0x54, 0x54, 0x54, 0x20}, // s
    {0x04, 0x3F, 0x44, 0x40, 0x20}, // t
    {0x3C, 0x40, 0x40, 0x20, 0x7C}, // u
    {0x1C, 0x20, 0x40, 0x20, 0x1C}, // v
    {0x3C, 0x40, 0x30, 0x40, 0x3C}, // w
    {0x44, 0x28, 0x10, 0x28, 0x44}, // x
    {0x0C, 0x50, 0x50, 0x50, 0x3C}, // y
    {0x44, 0x64, 0x54, 0x4C, 0x44}, // z
    {0x00, 0x08, 0x36, 0x41, 0x00}, // {
    {0x00, 0x00, 0x7F, 0x00, 0x00}, // |
    {0x00, 0x41, 0x36, 0x08, 0x00}, // }
    {0x08, 0x04, 0x08, 0x10, 0x08}, // ~
};

/**
 * @brief 在缓存中绘制一个字符
 * @param x X坐标 (0-127)
 * @param y Y坐标 (0-63)
 * @param ch 要显示的字符
 * @param color 颜色 (0=黑色, 1=白色)
 * @return 返回字符宽度（用于连续显示）
 */
uint8_t OLED_DrawChar(uint8_t x, uint8_t y, char ch, uint8_t color)
{
    // 检查坐标是否越界
    if (x >= OLED_WIDTH - 5 || y >= OLED_HEIGHT - 7)
    {
        return 0;
    }
    
    // 只支持可打印的ASCII字符 (32-126)
    if (ch < 32 || ch > 126)
    {
        ch = ' '; // 不支持的字符显示为空格
    }
    
    // 获取字符在字体库中的索引
    uint8_t index = ch - 32;
    
    // 绘制字符（5列，每列7个像素）
    for (uint8_t col = 0; col < 5; col++)
    {
        uint8_t data = font_5x7[index][col];
        
        for (uint8_t row = 0; row < 7; row++)
        {
            if (data & (1 << row))
            {
                OLED_DrawPixel(x + col, y + row, color);
            }
            else if (color == 0)
            {
                // 如果是黑色字符，需要清除背景
                OLED_DrawPixel(x + col, y + row, 1);
            }
        }
    }
    
    // 返回字符宽度 + 1像素间距
    return 6;
}

/**
 * @brief 在缓存中显示字符串
 * @param x 起始X坐标 (0-127)
 * @param y 起始Y坐标 (0-63)
 * @param str 要显示的字符串
 * @param color 颜色 (0=黑色, 1=白色)
 * @note 字符串会自动换行（如果超出屏幕宽度）
 */
void OLED_DrawString(uint8_t x, uint8_t y, const char* str, uint8_t color)
{
    uint8_t cur_x = x;
    uint8_t cur_y = y;
    
    while (*str != '\0')
    {
        // 检查是否需要换行
        if (cur_x > OLED_WIDTH - 6)
        {
            cur_x = 0;
            cur_y += 8; // 下一行（8像素间距）
            
            // 检查是否超出屏幕底部
            if (cur_y > OLED_HEIGHT - 8)
            {
                break; // 超出屏幕，停止显示
            }
        }
        
        // 处理换行符
        if (*str == '\n')
        {
            cur_x = 0;
            cur_y += 8;
            str++;
            
            if (cur_y > OLED_HEIGHT - 8)
            {
                break;
            }
            continue;
        }
        
        // 绘制字符并移动光标
        cur_x += OLED_DrawChar(cur_x, cur_y, *str, color);
        str++;
    }
}

/**
 * @brief 在缓存中显示数字
 * @param x X坐标 (0-127)
 * @param y Y坐标 (0-63)
 * @param num 要显示的数字
 * @param color 颜色 (0=黑色, 1=白色)
 */
void OLED_DrawNumber(uint8_t x, uint8_t y, int32_t num, uint8_t color)
{
    char buffer[12]; // 足够存储 int32 的字符串形式
    
    // 将数字转换为字符串
    if (num == 0)
    {
        buffer[0] = '0';
        buffer[1] = '\0';
    }
    else
    {
        uint8_t i = 0;
        bool negative = false;
        
        if (num < 0)
        {
            negative = true;
            num = -num;
        }
        
        // 反向存储数字
        while (num > 0)
        {
            buffer[i++] = '0' + (num % 10);
            num /= 10;
        }
        
        if (negative)
        {
            buffer[i++] = '-';
        }
        
        buffer[i] = '\0';
        
        // 反转字符串
        for (uint8_t j = 0; j < i / 2; j++)
        {
            char temp = buffer[j];
            buffer[j] = buffer[i - 1 - j];
            buffer[i - 1 - j] = temp;
        }
    }
    
    OLED_DrawString(x, y, buffer, color);
}

/**
 * @brief 在缓存中显示浮点数
 * @param x X坐标 (0-127)
 * @param y Y坐标 (0-63)
 * @param num 要显示的浮点数
 * @param decimal 小数点后位数 (0-6)
 * @param color 颜色 (0=黑色, 1=白色)
 */
void OLED_DrawFloat(uint8_t x, uint8_t y, float num, uint8_t decimal, uint8_t color)
{
    char buffer[16];
    
    // 限制小数位数
    if (decimal > 6) decimal = 6;
    
    // 处理负号
    uint8_t idx = 0;
    if (num < 0)
    {
        buffer[idx++] = '-';
        num = -num;
    }
    
    // 整数部分
    int32_t int_part = (int32_t)num;
    float frac_part = num - int_part;
    
    // 转换整数部分
    if (int_part == 0)
    {
        buffer[idx++] = '0';
    }
    else
    {
        char temp[12];
        uint8_t temp_idx = 0;
        
        while (int_part > 0)
        {
            temp[temp_idx++] = '0' + (int_part % 10);
            int_part /= 10;
        }
        
        // 反转
        while (temp_idx > 0)
        {
            buffer[idx++] = temp[--temp_idx];
        }
    }
    
    // 小数部分
    if (decimal > 0)
    {
        buffer[idx++] = '.';
        
        for (uint8_t i = 0; i < decimal; i++)
        {
            frac_part *= 10;
            uint8_t digit = (uint8_t)frac_part;
            buffer[idx++] = '0' + digit;
            frac_part -= digit;
        }
    }
    
    buffer[idx] = '\0';
    OLED_DrawString(x, y, buffer, color);
}
